package cn.tpshion.devops.handle;

import cn.tpshion.devops.node.data.SftpData;
import cn.tpshion.devops.node.support.MsgSftpProgressMonitor;
import cn.tpshion.devops.node.support.NodeContext;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.io.FileInputStream;
import java.util.Objects;
import java.util.Properties;

@Slf4j
public class SFTPHandle implements AutoCloseable {

    private Session session;

    private ChannelSftp sftp;

    private NodeContext nodeContext;

    private SSEHandle sseHandle;

    public SFTPHandle(SftpData sftpData, NodeContext nodeContext, SSEHandle sseHandle) throws Exception {
        this.nodeContext = nodeContext;
        this.sseHandle = sseHandle;
        conn(sftpData);
    }

    private void conn(SftpData sftpData) throws Exception{
        JSch jSch = new JSch();
        session = jSch.getSession(sftpData.getUsername(), sftpData.getHost(), sftpData.getPort());
        session.setPassword(sftpData.getPassword());
        Properties sshConfig = new Properties();
        sshConfig.put("StrictHostKeyChecking", "no");
        session.setConfig(sshConfig);
        session.connect(3000);
        sftp = (ChannelSftp) session.openChannel("sftp");
        sftp.connect(10000);
    }

    public void closeConn(){
        if(Objects.nonNull(sftp)){
            sftp.disconnect();
        }

        if(Objects.isNull(session)){
            return;
        }

        if(session.isConnected()){
            session.disconnect();
        }
    }

    private boolean isDirExist(String path){
        try {
            SftpATTRS sftpATTRS = sftp.lstat(path);
            return sftpATTRS.isDir();
        }catch (Exception e){
            return false;
        }
    }

    private boolean createDir(String path){
        log.info("createDir path:{}", path);
        try {
            if(isDirExist(path)){
                sftp.cd(path);
                return true;
            }
            String[] pathArray = path.split(File.separator);
            StringBuffer filePath = new StringBuffer(File.separator);
            for (String item : pathArray) {
                if(StringUtils.isBlank(item)){
                    continue;
                }
                log.info("createDir item:{}", item);
                filePath.append(item + File.separator);
                if(isDirExist(filePath.toString())){
                    sftp.cd(filePath.toString());
                }else{
                    sftp.mkdir(filePath.toString());
                    sftp.cd(filePath.toString());
                }
            }
            sftp.cd(path);
            return true;
        }catch (Exception e){
            return false;
        }
    }

    public void uploadFile(SftpData data) throws Exception{
        log.info("uploadFile data:{}", data);
        createDir(data.getRemotePath());
        File file = new File(data.getLocalPath() + File.separator + data.getFileName());
        try (FileInputStream in = new FileInputStream(file)){
            sftp.put(in, data.getFileName(), new MsgSftpProgressMonitor(sseHandle, nodeContext));
        }
    }

    /**
     * 批量上传文件（不传文件名时）
     * @param data
     * @throws Exception
     */
    public void batchUploadFile(SftpData data) throws Exception{
        log.info("batchUploadFile data:{}", data);
        File file = new File(data.getLocalPath());
        File[] files = file.listFiles();
        if(ObjectUtils.isEmpty(files)){
            return;
        }
        for (File tagetFile : files) {
            if(tagetFile.isFile() && tagetFile.getName().indexOf("bak") == -1){
                log.info("batchUploadFile tagetFile:{}", tagetFile.getName());
                data.setFileName(tagetFile.getName());
                uploadFile(data);
            }
            if(tagetFile.isDirectory()){
                SftpData sftpData = new SftpData();
                BeanUtils.copyProperties(data, sftpData);
                sftpData.setLocalPath(data.getLocalPath() + File.separator + tagetFile.getName());
                sftpData.setRemotePath(data.getRemotePath() + File.separator + tagetFile.getName());
                batchUploadFile(sftpData);
            }
        }
    }

    @Override
    public void close() throws Exception {
        closeConn();
    }
}
